package com.gitee.wsl.data.pool.sample

import com.gitee.wsl.data.pool.AsyncPool
import com.gitee.wsl.data.pool.Pool
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext

class AsyncPoolImp<T>(
    val maxSize:Int,
    val base:Pool<T>
):AsyncPool<T> {
    override val capacity: Int get() = base.capacity

    private val availableItemsSemaphore = Semaphore(maxSize)
    private val itemsAccessMutex = Mutex()

    override suspend fun acquire(): T? {
        availableItemsSemaphore.acquire()

        return try {
            itemsAccessMutex.withLock {
                base.acquire()
            }
        }catch (th: Throwable) {
            availableItemsSemaphore.release()
            throw th
        }
    }

    override suspend fun dispose() {
        itemsAccessMutex.withLock {
            base.dispose()
        }
    }

    override suspend fun releaseAll(variables: List<T>) {
        itemsAccessMutex.withLock {
            base.releaseAll(variables)
        }
    }

     override suspend fun release(instance: T): Boolean {
       return itemsAccessMutex.withLock {
            withContext(NonCancellable) {
                val ret = base.release(instance)
                availableItemsSemaphore.release()
                ret
            }
        }
    }
}

fun<T> Pool<T>.toAsync(maxSize:Int) = AsyncPoolImp(maxSize,this)